// eee.Sheffield.PZ.Imaging
//
// Copyright ?Ping Zou, 2007
// sg71.cherub@gmail.com

namespace eee.Sheffield.PZ.Imaging
{
	using System;
	using System.IO;
	using System.Drawing;
	using System.Drawing.Imaging;    
    using eee.Sheffield.PZ.Math;
	using System.Collections;
    using eee.Sheffield.PZ.Imaging.ImageFilter;

	/// <summary>
	/// consequtive scanline tracking
	/// </summary>
	public class ConsequtiveScanlineTracking 
	{
		public PZPoint cp = new PZPoint();		// center point
		public PZPoint ep1 = new PZPoint();		// edge point 1
		public PZPoint ep2 = new PZPoint();		// edge point 2
 		public PZDirection vd = new PZDirection();	// vessel direction
		public int d = 0;			// forward step
		public PZScanline lastsl = new PZScanline();	// last scanline, contains the init values
		public PZScanline currentsl = new PZScanline();	// current scanline
		public bool isfit = true;
		public string exit_msg;
		/// <summary>
		/// empty constructor
		/// </summary>
		public ConsequtiveScanlineTracking() {}

		/// <summary>
		/// constructor
		/// </summary>
		/// <param name="inputp">center point</param>
		/// <param name="inputvd">vessel direction</param>
		/// <param name="inputsl">last scanline</param>
		/// <param name="inputd">forward step</param>
		public ConsequtiveScanlineTracking(PZPoint inputp, PZDirection inputvd, 
			PZScanline inputsl, int inputd)
		{
			cp.MemCopyFrom(inputp);
			vd.MemCopyFrom(inputvd);
			d = inputd;
			lastsl = inputsl;
			ep1 = new PZPoint();
			ep2 = new PZPoint();
			
			// -- init current scanline
			int width = lastsl._widthOfScanline;
			int s = lastsl._sampleRate;
			double c = lastsl._c;
			double r = lastsl._r;
			double mu = lastsl._mu;
			double B = lastsl._B;
			currentsl = new PZScanline(width, s, c, r, mu, B);
		} // PZInterpolateScanline(PZPoint, int)

		/// <summary>
		/// scanline tracking,
		/// </summary>
		/// <param name="srcImg"></param>
		/// <returns></returns>
		public Bitmap Apply(Bitmap srcImg)
		{
			// -- prepare varibales;
			int width = srcImg.Width;
			int height = srcImg.Height;
			int widthofscanline = currentsl._widthOfScanline;
			int samplerate = currentsl._sampleRate;
			int halfwidth = widthofscanline / 2;
			double c = lastsl._c;
			double r = lastsl._r;
			double mu = lastsl._mu;
			double B = lastsl._B;

			// -- prepare center point array
			int lengthcp = 5;	// length of center point array
			PZPoint[] cparray = new PZPoint[lengthcp];
			for (int i = 0; i < lengthcp; i ++)
				cparray[i] = new PZPoint(0.0, 0.0);

			// -- prepare a template PZScanline;
			PZScanline tempsl = new PZScanline(widthofscanline, samplerate, c, r, mu, B);           

			// -- preapre extract scanline
			PZDirection sd = new PZDirection(vd);
			sd.GetNormalDirection();		// scanline direction

			// -- prepare for debug file
            //string filename = "scanline_record.txt";
            //FileStream fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
            //StreamWriter w = new StreamWriter(fs);

            //string cpstring, vdstring, cparraystring;
            //w.WriteLine();
            //w.WriteLine(String.Format("{0,-10}{1,-10}{2,-20}{3,-20}","length","Start","CP","D"));
            //cpstring = cp.ToString();
            //vdstring = vd.ToString();
            //w.WriteLine(String.Format("{0,-10}{1,-10}{2,-20}{3,-20}",tempsl.length," ",cpstring,vdstring));
            //w.WriteLine(String.Format("{0,-10}{1,-10}{2,-20}{3,-20}{4,-10}{5,-10}{6,-10}{7,-10}{8,-10}"," ", "tempsl", "CP", "CP'", "c", "r", "mu", "B","converge"));
			
            // -- do consequtive scanline fitting
			for (int i = 0; i < lengthcp; i ++)
			{
				// current center point
				cparray[i].ExtendFrom(cp, vd, (double) (i + d - lengthcp / 2));
                //cparraystring = cparray[i].ToString()  + " -> ";
                //w.Write(String.Format("{0,-10}{1,-10}{2,-20}"," ", i + 1, cparraystring));

				// extract scanline
				ExtractScanline exsl = new ExtractScanline(cparray[i], sd, samplerate, widthofscanline);
				exsl.Apply(srcImg);

				// fitting the scanline
                tempsl._fg.MemCopyFrom(exsl.Fg);
                Array.Copy(exsl.Fp, tempsl._fp, exsl.Fp.Length);				
				System.Console.Write("tempsl(" + (i + 1) + ")... ");
                tempsl.NMMin();
                tempsl.WriteFile("scanline.txt");

                //if (!tempsl.IsFit())
                //{
                //    // try matched filter
                //    SunScanline sunSL = new SunScanline(r, 0.02);                    
                //    sunSL.ScanlineProfile = new PZMath_vector(tempsl._fg);
                //    for (int j = 0; j < sunSL.ScanlineProfile.Size; j++)
                //        sunSL.ScanlineProfile[j] = 255 - sunSL.ScanlineProfile[j];
                //    sunSL.Analysis();
                //    tempsl._r = sunSL.Radius;
                //    tempsl._c = sunSL.Centre;
                //    tempsl._mu = mu;
                //    tempsl._B = sunSL.BackgroundLevel;
                //}
                
				// return the estimate of center point
                // update centre point only when scanline profile fitted
                //if (tempsl.IsFit())
				cparray[i].ExtendFrom(cparray[i], sd, tempsl._c - halfwidth);

                //w.Write(String.Format("{0,-20}", cparray[i].ToString()));
                //w.WriteLine(String.Format("{0,-10:0.00}{1,-10:0.00}{2,-10:0.00}{3,-10:0.00}",tempsl.c, tempsl.r, tempsl.mu, tempsl.B));
			}

            //string cpFileName = "centre points.txt";
            //FileStream cpFileStream = new FileStream(cpFileName, FileMode.Create, FileAccess.Write);
            //StreamWriter cpWriter = new StreamWriter(cpFileStream);
            //for (int i = 0; i < lengthcp; i++)
            //    cpWriter.WriteLine(String.Format("{0, -10:f}{1, -10:f}", cparray[i].x, cparray[i].y));
            //cpWriter.Flush();
            //cpWriter.Close();
            //cpFileStream.Close();

			// fitting the center point line, estimate the vessel direction
			PZDirection vd1;
			vd1 = PZScanline.EstimateDirection(cparray);			            
            vd.MemCopyFrom(vd1);

            //w.WriteLine();
            //w.WriteLine(String.Format("{0,30}{1,20}","VD",vd.ToString()));
			
			sd.MemCopyFrom(vd);
			sd.GetNormalDirection();

			// extract another scanline;
			ExtractScanline exsl1 = new ExtractScanline(cparray[lengthcp / 2], sd, samplerate, widthofscanline);
			exsl1.Apply(srcImg);

            currentsl._fg.MemCopyFrom(exsl1.Fg);
            Array.Copy(exsl1.Fp, currentsl._fp, exsl1.Fp.Length);
			System.Console.Write("current sl ...");

            //currentsl.DrawScanline("current scanline.bmp", srcImg);

			// fiiting the current scanline;
			currentsl.NMMin();
            currentsl.WriteFile("current sl scanline.txt");

            //if (!currentsl.IsFit())
            //{
            //    // shrink scanline and try again
            //    ExtractScanline exShrinkSL = new ExtractScanline(cparray[lengthcp / 2], sd, samplerate, (int)(widthofscanline * 0.6));
            //    exShrinkSL.Apply(srcImg);
            //    PZScanline shrinkSL = new PZScanline(exShrinkSL.Fg.Size, samplerate, c, r, mu, B);
            //    shrinkSL._fg.MemCopyFrom(exShrinkSL.Fg);
            //    Array.Copy(exShrinkSL.Fp, shrinkSL._fp, exShrinkSL.Fp.Length);
            //    shrinkSL.NMMin();
            //    if (shrinkSL.IsFit())
            //        currentsl = shrinkSL;
            //}

            //if (!currentsl.IsFit())
            //{
            //    // try matched filter
            //    SunScanline sunSL = new SunScanline(r, 0.02);
            //    sunSL.ScanlineProfile = currentsl._fg;
            //    sunSL.Analysis();
            //    currentsl._r = sunSL.Radius;
            //    currentsl._c = sunSL.Centre;
            //    currentsl._mu = mu;
            //    currentsl._B = sunSL.BackgroundLevel;
            //}

			System.Console.WriteLine();
			if (!currentsl.IsFit())
			{
				exit_msg = currentsl.exit_msg;
				isfit = false;
			}

            //currentsl.WriteFile("scanline.txt");
            //w.Write(String.Format("{0,-10}", currentsl.length));

			currentsl._widthOfScanline = (int) System.Math.Ceiling (currentsl._r * 3);
            if (currentsl._widthOfScanline < 12)
                currentsl._widthOfScanline = 12;
            //if (currentsl.widthofscanline > 16)
            //	currentsl.widthofscanline = 16;
			currentsl._length = currentsl._widthOfScanline * currentsl._sampleRate;
						
			// return cp and ep estimate
			cp.ExtendFrom(cparray[lengthcp / 2], sd, currentsl._c - halfwidth);
			ep1.ExtendFrom(cparray[lengthcp / 2], sd, (currentsl._c - currentsl._r) - halfwidth);
			ep2.ExtendFrom(cparray[lengthcp / 2], sd, (currentsl._c + currentsl._r) - halfwidth);

            //cpstring = cp.ToString();
            //cparraystring = cparray[lengthcp / 2].ToString() + " -> ";
            //w.WriteLine(String.Format("{1,-10}{2,-20}{3,-20}{4,-10:0.00}{5,-10:0.00}{6,-10:0.00}{7,-10:0.00}{8,-10}",
            //    " ", "currentsl", cparraystring, cpstring, currentsl.c, currentsl.r, currentsl.mu, currentsl.B, " "));
            //w.WriteLine();
            //w.WriteLine(String.Format("{0,-10}{1,-10}{2,-20}{3,-20}",
            //    currentsl.length," ", cpstring, vdstring));			            
            //w.Close();
            //fs.Close();

			// create new image only for return purpose
            Bitmap dstImg = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            return dstImg;
		} // Apply()

	} // ConsequtiveScanlineTracking
}
